#include <errno.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <iostream>
#include "util/log.h"
#include "server.h"
#include "eventloop.h"
#include "util/timeutil.h"

using namespace std;



namespace dong{


Server::Server(Eventloop * loop ,const std::string &ip, short port)
        :loop_(loop),linkcounts_(0),ip_(ip),port_(port){
    signal(SIGPIPE, SIG_IGN);

}
void Server::start() {
    servlink_ = Link::listen(ip_, port_);
    if(!servlink_){
        log_error("servlink_");
    }
    listenfd_ = servlink_->fd();
    channel_ = new Channel(loop_,listenfd_);
    channel_->enableRead(true);
    channel_->onRead(std::bind(&Server::handleAccept,this));
    servlink_->attachChannel(channel_);
    servlink_->attachLoop(loop_);
    log_info("server listen on %s:%hd",ip_.c_str(),port_);
}
Server::~Server(){
	for(auto & sev: servlets_){
        sev->free();
        delete sev;
    }
	this->servlets_.clear();
	delete servlink_;
    delete loop_;
    delete channel_;
}

int Server::handleClose(Session *sess){
    Link *link = sess->link;
    for(auto & sev : servlets_)
    {
        auto ret =  sev->onClose(sess);
    }
	this->linkcounts_ --;
	log_debug("delete link %s:%d, fd: %d, links: %d",
		link->remote_ip, link->remote_port, link->fd(), this->linkcounts_);
	this->sessions_.erase(sess->id);
	delete link;
	delete sess;
	return 0;
}


Session* Server::getSession(int64_t sess_id){
	std::map<int64_t, Session *>::iterator it;
	it = sessions_.find(sess_id);
	if(it == sessions_.end()){
		return NULL;
	}
	return it->second;
}


void Server::addServlet(Servlet *slet) {
    slet->init();
    this->servlets_.push_back(slet);
}

Session *Server::handleAccept() {

    Link *link = servlink_->accept();
    if(link == NULL){
        log_error("accept failed! %s", strerror(errno));
        return NULL;
    }
    link->noblock();
    link->create_time = timeutil::getCurremtMs();
    link->active_time = link->create_time;

    Session *sess = new Session();
    sess->link = link;
    this->sessions_[sess->id] = sess;

    for(auto &serv : servlets_) {
        auto ret = serv->onConnect(sess);
        if(ret <0){
            delete link;
            delete sess;
            return  NULL;
        }
    }
    this->linkcounts_ ++;
    log_debug("new link from %s:%d, fd: %d, links: %d",
              link->remote_ip, link->remote_port, link->fd(), this->linkcounts_);
    Channel *ch = new Channel(loop_,link->fd());
    ch->enableReadWrite(true,false);
    ch->onRead(std::bind(&Server::handleRead,this,sess));
    ch->onWrite(std::bind(&Server::handleWrite,this,sess));
    link->attachLoop(loop_);
    link->attachChannel(ch);
    return sess;
}

int Server::handleRead(Session *sess) {

    Link *link = sess->link;
    if(link->error()){
        return -1;
    }
    int len = link->tranformMessage();
    if(len <= 0){
        this->handleClose(sess);
        return -1;
    }
    for(auto & v : servlets_)
    {
        auto ret = v->onMessage(sess);
        if(ret > 0){
            auto ch = link->getChannel();
            ch->enableWrite(true);
            ch->onWrite(std::bind(&Link::write,link));
        }else if(ret < 0)
        {
           this->handleClose(sess);
            return -1;
        }
    }

    return 0;
}

int  Server::handleWrite(Session *sess) {
    Link *link = sess->link;
    if(link->error()){
        return 0;
    }
    int len = link->write();
    if(len <= 0){
        log_debug("fd: %d, write: %d, delete link", link->fd(), len);
        this->handleClose(sess);
        return -1;
    }
    return 0;
}


};
